//
//  TTMemoryCache.m
//  Tint
//
//  Created by Kevin Wu on 8/23/12.
//  Copyright (c) 2012 Telligenty. All rights reserved.
//

#import "TTMemoryCache.h"

@implementation TTMemoryCache


TTSynthesizeSingleton(TTMemoryCache);


#pragma mark - Memory

- (id)init
{
    self = [super init];
    if ( self ) {
        _cacheDictionary = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (void)dealloc
{
    [super dealloc];
}


#pragma mark - Override


- (void)removeCacheForKey:(NSString *)key name:(NSString *)name
{
    [_executeLock lock];
    
    NSMutableDictionary *cache = [_cacheDictionary objectForKey:name];
    if ( cache ) {
        [cache removeObjectForKey:key];
        
        if ( [cache count] < 1 ) {
            [_cacheDictionary removeObjectForKey:name];
        }
    }
    
    [_executeLock unlock];
}



- (void)cleanAllCache
{
    [_executeLock lock];
    
    NSArray *names = [_cacheDictionary allKeys];
    for ( int i=0; i<[names count]; ++i ) {
        NSString *name = [names objectAtIndex:i];
        NSMutableDictionary *cache = [_cacheDictionary objectForKey:name];
        
        NSArray *keys = [cache allKeys];
        for ( int j=0; j<[keys count]; ++j ) {
            NSString *key = [keys objectAtIndex:j];
            NSDictionary *item = [cache objectForKey:key];
            if ( ![self isItemValid:item] ) {
                [cache removeObjectForKey:key];
            }
        }
        
        if ( [cache count] < 1 ) {
            [_cacheDictionary removeObjectForKey:name];
        }
    }
    
    [_executeLock unlock];
}

- (void)cleanCacheByName:(NSString *)name
{
    [_executeLock lock];
    
    NSMutableDictionary *cache = [_cacheDictionary objectForKey:name];
    if ( cache ) {
        NSArray *keys = [cache allKeys];
        for ( int j=0; j<[keys count]; ++j ) {
            NSString *key = [keys objectAtIndex:j];
            NSDictionary *item = [cache objectForKey:key];
            if ( ![self isItemValid:item] ) {
                [cache removeObjectForKey:key];
            }
        }
        
        if ( [cache count] < 1 ) {
            [_cacheDictionary removeObjectForKey:name];
        }
    }
    
    [_executeLock unlock];
}



- (void)clearAllCache
{
    [_executeLock lock];
    [_cacheDictionary removeAllObjects];
    [_executeLock unlock];
}

- (void)clearCacheByName:(NSString *)name
{
    [_executeLock lock];
    [_cacheDictionary removeObjectForKeyIfNotNil:name];
    [_executeLock unlock];
}


#pragma mark - Public

- (id)objectForKey:(NSString *)key
{
    return [self objectForKey:key name:TTCacheNameDefault];
}

- (id)objectForKey:(NSString *)key name:(NSString *)name
{
    id object = nil;
    [_executeLock lock];
    NSDictionary *cache = [_cacheDictionary objectForKey:name];
    NSDictionary *item = [cache objectForKey:key];
    if ( [self isItemValid:item] ) {
        object = [item objectForKey:TTCacheItemCacheObject];
    }
    [_executeLock unlock];
    return object;
}

- (BOOL)setObject:(id)object forKey:(NSString *)key
{
    return [self setObject:object forKey:key withTimeoutInterval:_defaultTimeoutInterval name:TTCacheNameDefault];
}

- (BOOL)setObject:(id)object forKey:(NSString *)key name:(NSString *)name
{
    return [self setObject:object forKey:key withTimeoutInterval:_defaultTimeoutInterval name:name];
}

- (BOOL)setObject:(id)object forKey:(NSString *)key withTimeoutInterval:(NSTimeInterval)timeoutInterval
{
    return [self setObject:object forKey:key withTimeoutInterval:timeoutInterval name:TTCacheNameDefault];
}

- (BOOL)setObject:(id)object forKey:(NSString *)key withTimeoutInterval:(NSTimeInterval)timeoutInterval name:(NSString *)name
{
    if (TTIsStringWithText(key) && 
        TTIsStringWithText(name))
    {
        
        BOOL result = NO;
        
        [_executeLock lock];
        
        if ( [self createCacheForName:name] ) {
            
            NSMutableDictionary *item = [self addItemWithKey:key name:name timeoutInterval:timeoutInterval];
            
            if ( object ) {
                [item setObject:object forKey:TTCacheItemCacheObject];
            } else {
                [item removeObjectForKey:TTCacheItemCacheObject];
            }
            
            result = YES;
        }
        
        [_executeLock unlock];
        
        return result;
    }
    return NO;
}

@end
